package org.btik.light.tool;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MDUtil {

    /**
     * @param algorithm @see <a href="https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#messagedigest-algorithms">消息摘要</a>
     *                  摘要</a>
     * @return 当找不到算法时返回null
     */
    public static byte[] digest(Algorithm algorithm, byte[] data) {
        try {
            MessageDigest messageDigest = MessageDigest.getInstance(algorithm.getAlgorithmName());
            return messageDigest.digest(data);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param algorithm @see <a href="https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#messagedigest-algorithms">消息摘要</a>
     *                  摘要</a>
     * @return 当找不到算法时返回null
     */
    public static byte[] digest(Algorithm algorithm, byte[]... data) {
        try {
            MessageDigest messageDigest = MessageDigest.getInstance(algorithm.getAlgorithmName());
            for (byte[] datum : data) {
                messageDigest.update(datum);
            }
            return messageDigest.digest();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param algorithm 算法
     * @param data      待计算摘要的内容
     * @return 返回摘要值的16进制字符串
     */
    public static String digestAsHex(Algorithm algorithm, byte[] data) {
        return ByteUtil.toHexString(digest(algorithm, data));
    }

    /**
     * @param algorithm 算法
     * @param data      待计算摘要的内容
     * @return 返回摘要值的16进制字符串
     */
    public static String digestAsHex(Algorithm algorithm, String data) {
        return ByteUtil.toHexString(digest(algorithm, data));
    }

    /**
     * @param algorithm 算法
     * @param data      待计算摘要的内容
     * @return 返回摘要值的16进制字符串
     */
    public static byte[] digest(Algorithm algorithm, String data) {
        return digest(algorithm, data.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * @param algorithm 算法
     * @param data      待计算摘要的内容
     * @return 返回摘要值的16进制字符串
     */
    public static byte[] digestAsHexBytes(Algorithm algorithm, byte[] data) {
        return ByteUtil.toHexBytes(digest(algorithm, data));
    }

    public enum Algorithm {
        /**
         * The MD2 message digest algorithm as defined in <a href="https://tools.ietf.org/html/rfc1319">RFC 1319</a>).
         */
        MD2("MD2", 16),
        /**
         * The MD5 message digest algorithm as defined in <a href="https://tools.ietf.org/html/rfc1321">RFC 1321</a>.
         */
        MD5("MD5", 16),

        /**
         * Hash algorithms defined in <a href="https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf">FIPS PUB 180-4</a>.<br>
         * Secure hash algorithms - SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256 - for computing a condensed representation of electronic data (message). <br>
         * When a message is input to a hash algorithm, the result is an output called a message digest. A message digest ranges in length from 160-512 bits, depending on the algorithm.
         */
        SHA_1("SHA-1", 20),
        SHA_224("SHA-224", 28),
        SHA_256("SHA-256", 32),
        SHA_384("SHA-384", 48),
        SHA_512_224("SHA-512/224", 28),
        SHA_512_256("SHA-512/256", 32),
        /**
         * Permutation-based hash and extendable-output functions as defined in <a href="https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf">FIPS PUB 202</a>. <br>
         * An input message length can vary; the length of the output digest is fixed.  <br>
         * SHA3-224 produces a 224 bit digest. SHA3-256 produces a 256 bit digest. <br>
         * SHA3-384 produces a 384 bit digest. <br>
         * SHA3-512 produces a 512 bit digest.<br>
         */
        SHA3_224("SHA3-224", 28),
        /**
         * @see #SHA3_224
         */
        SHA3_256("SHA3-256", 32),
        SHA3_384("SHA3-384", 48),
        SHA3_512("SHA3-512", 64);

        Algorithm(String algorithmName, int length) {
            this.algorithmName = algorithmName;
            this.length = length;
        }

        /**
         * 用于获取真正的算法
         */
        private final String algorithmName;

        /**
         * 摘要字节数
         */
        private final int length;

        public String getAlgorithmName() {
            return algorithmName;
        }

        public int getLength() {
            return length;
        }
    }
}
